// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

import qrj_math from "./qrj_math";


export default class qrj_node {
    /**
 *      自定义 FIND 
 * @param node  寻找节点 
 * @param pn   路径
 * @param type   返回类型   null 返回 cc.node
 */
    public static findChildByName(node: cc.Node, pn: string, type = null): any {
        let path = pn.split("/");

        let r = node;
        for (let i = 0; i < path.length; i++) {
            const e = path[i];
            r = r.getChildByName(e);
            if (r == null) {
                cc.error("qrjTools.findChildByName 出错!  " + node.name + "中查找 " + pn);
                cc.error("节点:>" + e + "<没有找到");
                return null;
            }
        }

        if (type == null) {
            return r;
        } else {
            let t = r.getComponent(type);
            if (t == null) {
                cc.error("qrjTools.findChildByName 出错!  节点下没有找到 对应组件!  " + pn);
                return null;
            } else {
                return t;
            }
        }
    }

    /**
*     设置  按钮 事件
* @param button  按钮节点
* @param node   事件节点
* @param file   事件脚本名称
* @param fun    事件 函数 名称
* @param data   参数
*/
    public static set_button_event(button: cc.Node, node: cc.Node, file: string, fun: string, data = null): void {
        let cb = button.getComponent(cc.Button);
        if (cb == null) {
            cb = button.addComponent(cc.Button);
        }
        var queding_ceh = new cc.Component.EventHandler();
        queding_ceh.target = node; //这个 node 节点是你的事件处理代码组件所属的节点
        queding_ceh.component = file;//这个是代码文件名
        queding_ceh.handler = fun;
        queding_ceh.customEventData = data;
        cb.clickEvents.length = 0 // 清空数组
        cb.clickEvents.push(queding_ceh);
    }

    /**
     *    设置  click 按钮事件
     */
    public static set_click_event(button: cc.Node, fun: Function, is_once = false) {
        let cb = button.getComponent(cc.Button);
        if (cb == null) {
            cb = button.addComponent(cc.Button);
        }
        button.targetOff("click");

        if (is_once == true) {
            button.once("click", () => {
                fun && fun();
            });
        } else {
            button.on("click", () => {
                fun && fun();
            });
        }
    }


    /**
     *        计算 节点 A 在   节点B 坐标系中的 位置
     *        转换后 , B的坐标0,0  , 取 A的 坐标
     */
    public static getAinBPos(node_a: cc.Node, node_b: cc.Node): cc.Vec2 {
        // let nv = node_a.parent.convertToWorldSpaceAR(node_a.getPosition());
        let nv = node_a.convertToWorldSpaceAR(cc.v2(0, 0));
        let r = node_b.convertToNodeSpaceAR(nv);
        return r;
    }

    /**
     *  将节点坐标 设置到 世界坐标
     * @param n  节点
     * @param wp   世界坐标  
     */
    public static set_node_world_position(n: cc.Node, wp: cc.Vec2): void {
        let t = n.parent.convertToNodeSpaceAR(wp);
        n.x = t.x;
        n.y = t.y;
    }

    /**
     *      播放节点上的动画 , 播放完成后 , 删除节点
     */
    public static play_anim_and_remove(n: cc.Node, an: string = null) {
        let anim: cc.Animation = n.getComponent(cc.Animation);
        anim.once('finished', () => { n.active = false });
        if (an == null) {
            anim.play();
        } else {
            anim.play(an);
        }
    }

    /**
     *       将 na节点 的父节点 更换为 nb, 保持 显示位置不变
     */
    public static node_set_parent(na: cc.Node, nb: cc.Node) {
        let wp = na.convertToWorldSpaceAR(cc.v2(0, 0));
        let np = nb.convertToNodeSpaceAR(wp);
        na.parent = nb;
        na.x = np.x;
        na.y = np.y;
    }

    /**
     *       将 na节点 对齐到 nb节点
     */
    public static node_align_otherNode(na: cc.Node, nb: cc.Node) {
        let wp = nb.convertToWorldSpaceAR(cc.v2(0, 0));
        let p = na.parent.convertToNodeSpaceAR(wp);
        na.x = p.x;
        na.y = p.y;
    }




    /**
     *    设置 节点 点击 事件
     */
    public static set_node_touch_event(n: cc.Node, start: Touch_event, move: Touch_event = null, end: Touch_event = null) {
        n.targetOff(cc.Node.EventType.TOUCH_START)
        n.targetOff(cc.Node.EventType.TOUCH_MOVE)
        n.targetOff(cc.Node.EventType.TOUCH_END)
        n.targetOff(cc.Node.EventType.TOUCH_CANCEL)

        start && n.on(cc.Node.EventType.TOUCH_START, (event: cc.Event.EventTouch) => {
            try {
                start(event);
            } catch (error) {
                cc.error(error);
            }
        });

        move && n.on(cc.Node.EventType.TOUCH_MOVE, (event: cc.Event.EventTouch) => {
            try {
                move(event);
            } catch (error) {
                cc.error(error);
            }
        });

        end && n.on(cc.Node.EventType.TOUCH_END, (event: cc.Event.EventTouch) => {
            try {
                end(event);
            } catch (error) {
                cc.error(error);
            }
        });

        end && n.on(cc.Node.EventType.TOUCH_CANCEL, (event: cc.Event.EventTouch) => {
            try {
                end(event);
            } catch (error) {
                cc.error(error);
            }
        });
    }

    public static touchPoint_nodePoint(n: cc.Node, te: cc.Event.EventTouch): cc.Vec2 {
        if (n == null || te == null) {
            return null;
        }
        let wp = te.getLocation();
        let np = n.convertToNodeSpaceAR(wp);
        return np;
    }

    /**
     *    设置 场景
     */
    public static load_scene(name: string) {
        let root = cc.director.getScene();
        root.removeAllChildren();
        cc.director.loadScene(name);
    }

    /**
     *    节点下 所有 节点 之显示一个
     */
    public static set_disp_in_nodes(pn: cc.Node, nn: string): cc.Node {
        let all = pn.children;
        for (let i = 0; i < all.length; i++) {
            all[i].active = all[i].name == nn;
        }
        return pn.getChildByName(nn);
    }



    /******************************************************
     *             设置图片成  黑白
     ******************************************************/
    static _sprite_builtin_gray_sprite: cc.Material = null;
    static _sprite_builtin_sprite: cc.Material = null;
    public static set_sprite_gray(spr: cc.Node | cc.Sprite, is_gray: boolean) {
        if (this._sprite_builtin_gray_sprite == null) {
            this._sprite_builtin_gray_sprite = cc.Material.getBuiltinMaterial("2d-gray-sprite");
            this._sprite_builtin_sprite = cc.Material.getBuiltinMaterial("2d-sprite");
        }
        let s: cc.Sprite = spr.getComponent(cc.Sprite);
        let cm: cc.Material = s.getMaterial(0);
        if (is_gray == true) {
            if (cm.name != this._sprite_builtin_gray_sprite.name) {
                s.setMaterial(0, this._sprite_builtin_gray_sprite);
            }
        } else {
            if (cm.name != this._sprite_builtin_sprite.name) {
                s.setMaterial(0, this._sprite_builtin_sprite);
            }
        }
    }

    /**
     *   设置 精灵 material
     */
    public static set_sprite_material(spr: cc.Node | cc.Sprite, mate: cc.Material = null) {
        if (mate == null) {
            mate = cc.Material.getBuiltinMaterial("2d-sprite");
        }

        let s: cc.Sprite = spr.getComponent(cc.Sprite);
        let cm: cc.Material = s.getMaterial(0);

        if (cm.name != mate.name) {
            s.setMaterial(0, mate);
        }
    }

    /**
     *     背景 AB 水平循环动作 (AB的宽度要大于,背景宽度)
     *   bg_node 需要填充的 背景节点
     *     an = A背景   bn = B背景
     */
    public static act_ab_loop(bg_node: cc.Node, an: cc.Node, bn: cc.Node, speed: number) {
        bg_node.anchorX = 0;

        an.anchorX = 0;
        bn.anchorX = 0;
        an.x = 0;
        bn.x = an.width;

        let a_1 = cc.moveBy(an.width / speed, -an.width, 0);
        let b_1 = cc.moveBy(an.width / speed, -an.width, 0);

        let a_2 = cc.callFunc(() => {
            an.x = bn.width;
        });
        let b_2 = cc.callFunc(() => {

        });

        let a_3 = cc.moveBy(bn.width / speed, -bn.width, 0);
        let b_3 = cc.moveBy(bn.width / speed, -bn.width, 0);

        let a_4 = cc.callFunc(() => {
        });
        let b_4 = cc.callFunc(() => {
            bn.x = an.width;
        });

        an.runAction(cc.repeatForever(cc.sequence(a_1, a_2, a_3, a_4)));
        bn.runAction(cc.repeatForever(cc.sequence(b_1, b_2, b_3, b_4)));
    }

    /**
     *    获得 当前场景 canvas
     */
    public static get_canvas(): cc.Canvas {
        return cc.director.getScene().getComponentInChildren(cc.Canvas);
    }


    /**
     *   路径 移动
     */
    public static path_move(n: cc.Node, path: cc.Node[], speed: number, fun: Function = null) {
        let last_angle = n.angle + 90;

        let t = cc.tween(n)
        let at = (a: cc.Node, b: cc.Node) => {
            let m = cc.v2(b.x - a.x, b.y - a.y);
            let f = qrj_math.sudu_2_xiangliang(m);
            t.by(f.y / speed, { x: m.x, y: m.y, angle: f.x - last_angle })
            last_angle = f.x;
        }
        for (let i = 0; i < path.length - 1; i++) {
            at(path[i], path[i + 1]);
        }
        t.call(() => {
            fun && fun();
        })
        t.start();
    }


    /**
     *    自动调整节点 到 合适尺寸  (等比例 缩放)
     */
    public static auto_node_size(n: cc.Node, w: number, h: number) {
        let nw = n.width;
        let nh = n.height;

        let nbili = nw / nh;  // 节点宽高比
        let mbili = w / h;

        if (nbili > mbili) { //// 节点 宽度 比较大
            n.width = w;
            n.height = w / nw * nh;

        } else {  ////// 节点高度 比较大
            n.height = h;
            n.width = h / nh * nw;
        }
    }

    /**
     *     获得 节点 对比 canvas 的 相对尺寸 , 用于(微信截图坐标转换)
     */
    public static get_relative_rect(n: cc.Node): cc.Rect {
        let canvas: cc.Canvas = this.get_canvas();

        let left_top: cc.Vec2 = cc.v2(-n.width * n.anchorX, n.height * n.anchorY);

        let nv = n.convertToWorldSpaceAR(left_top);
        nv.y = canvas.node.height - nv.y;

        let r = new cc.Rect();
        r.x = nv.x / canvas.node.width;
        r.y = nv.y / canvas.node.height;
        r.width = n.width / canvas.node.width;
        r.height = n.height / canvas.node.height;

        return r;
    }

    //  锁定按钮
    public lock_button(b: cc.Node | cc.Button, time = 1) {
        if (!b) return;
        let btn: cc.Button = null;
        if (b instanceof cc.Node) {
            btn = b.getComponent(cc.Button);
            if (!btn) return;
        } else {
            btn = b;
        }

        btn.enabled = false;
        setTimeout(() => {
            if (cc.isValid(btn.node))
                btn.enabled = true;
        }, time);
    }

    ////////// 赛贝尔曲线 移动
    public static bezier_to(n: cc.Node, mubiao: cc.Node, cs: cc.Vec2, cb: Function) {
        let bezier = [];
        bezier.push(cc.v2(n.x, n.y));
        bezier.push(cs);
        bezier.push(qrj_node.getAinBPos(mubiao, n.parent));

        n.runAction(cc.sequence(
            cc.bezierTo(1, bezier),
            cc.removeSelf(),
            cc.callFunc(() => { cb && cb(); })
        ));
    }

    ////////// 节点 跟踪
    public static genzong(n: cc.Node, mubiao: cc.Node, time = 0) {
        let p: cc.Vec2 = qrj_node.getAinBPos(mubiao, n.parent);
        if (time <= 0) {
            n.setPosition(p);
            mubiao.on('position-changed', () => {
                let p: cc.Vec2 = qrj_node.getAinBPos(mubiao, n.parent);
                n.setPosition(p);
            });
        } else {
            cc.tween(n).to(time, { x: p.x, y: p.y }, { easing: 'easeInCubic' }).start();
            mubiao.on('position-changed', () => {
                let p: cc.Vec2 = qrj_node.getAinBPos(mubiao, n.parent);
                cc.tween(n).to(time, { x: p.x, y: p.y }).start();
            });
        }
    }    

    ///////////计算 两个节点间距离
    public static get_space_2_node(a: cc.Node, b: cc.Node): number {
        let v1 = a.convertToWorldSpaceAR(cc.v2(0, 0));
        let v2 = b.convertToWorldSpaceAR(cc.v2(0, 0));
        return cc.v2(v2.x - v1.x, v2.y - v1.y).mag();
    }
    
    /////////// 计算 两个节点间 夹角的角度
    public static get_angle_2_node(a: cc.Node, b: cc.Node): number {
        let v1 = a.convertToWorldSpaceAR(cc.v2(0, 0));
        let v2 = b.convertToWorldSpaceAR(cc.v2(0, 0));
        return qrj_math.get_angle_2_position(v1, v2);
    }
}

/**
 *      触摸事件
 */
interface Touch_event {
    (event: cc.Event.EventTouch): void;
}